/*:
 * @plugindesc 让RPGMacker 支持MQTT协议进行消息对话;
 *
 * @author 玉米
 * @param host				
 * @desc 服务器地址 默认:127.0.0.1
 * @param port				
 * @desc 服务器端口 默认:8083
 * @param resourePath 				
 * @desc 资源路径 默认:/mqtt
 * @param username
 * @desc 用户名 默认: UUID
 * @param password
 * @desc 密码 默认: UUID
 * @param nickname
 * @desc 昵称
 * @param clientId
 * @desc 客户端ID 默认123456
 * @param enable
 * @desc 启用状态 on 启用, off禁用
 * @param mqttCustomLib
 * @desc mqtt客户端原始库启用状态 on 启用, off禁用
 * @param encryptionMD5
 * @desc md5加密启用状态 on 启用,off禁用
 * @help
 * 全局对象:$gameMqttClient
 * 其他插件可以通过来监听message消息写UI事件 $gameMqttClient.on("message",callback,packet);
 * 文档 https://www.npmjs.com/package/mqtt
 *
 * 附属安装MQTT服务器
 * [方法一]
 * 官网直接安装:https://www.emqx.com/zh/try?product=broker
 *
 * [方法二(推荐)]
 * Docker: https://www.runoob.com/docker/centos-docker-install.html
 * MQTT服务器Docker 安装方式: https://www.cnblogs.com/fangts/p/15147408.html
 *
 * 默认订阅topic
 *  客户端主题 : "/client/${clientId}/#"
 *  用户主题 : "/user/${username}/#"
 *  聊天室主题 : "/chat/room/public/#"
 *  远程控制主题 : "/device/control/${clientId}/#"
 *
 * Plugin Command:
 *   MqttClientMv send topic message                #发送消息到指定topic
 *   MqttClientMv sub topic                         #订阅消息topic
 *   MqttClientMv unsub topic                       #取消订阅消息topic
 *   MqttClientMv send_client clientId message      #给指定客户端发送消息
 *   MqttClientMv send_user username message        #给指定用户发送消息
 *   MqttClientMv send_public_room message          #给指定公共聊天室发送消息
 *   MqttClientMv send_room roomId message          #给指定聊天室发送消息
 */
(function() {

	function isNotBlank(value) {
		if (typeof value === "undefined") {
			return false;
		}

		if (value == null || value.trim().length == 0) {
			return false;
		}

		return true;
	}

	var parameters = PluginManager.parameters('MqttForRpgmakerMv');
	var enable = (isNotBlank(parameters["enable"]) && parameters["enable"] === 'on');
	var encryptionMD5 = (typeof parameters["encryptionMD5"] !== "undefined" && parameters["encryptionMD5"] ===
		'on');
	var mqttCustomLib = (typeof parameters["mqttCustomLib"] !== "undefined" && parameters["mqttCustomLib"] ===
		'on');

	//插件启用状态
	if (!enable) {
		return;
	}
	var MqttClientMv = function() {};

	MqttClientMv.loadJS = function(url, callback) {
		var script = document.createElement('script');
		var fn = callback || function() {};
		script.type = 'text/javascript';
		//IE
		if (script.readyState) {
			script.onreadystatechange = function() {
				if (script.readyState == 'loaded' || script.readyState == 'complete') {
					script.onreadystatechange = null;
					fn();
				}
			};
		} else {
			//其他浏览器
			script.onload = function() {
				fn();
			};
		}
		script.src = url;
		document.getElementsByTagName('head')[0].appendChild(script);
	}

	if (!mqttCustomLib) {
		MqttClientMv.loadJS("js/libs/mqtt.min.js", function() {});
	}

	encryptionMD5 = true;

	if (encryptionMD5) {
		MqttClientMv.loadJS("js/libs/md5.js", function() {});
	}

	var $MCP = MqttClientMv.prototype;

	MqttClientMv.nextUuid = function() {
		var s = [];
		var hexDigits = "0123456789abcdef";
		for (var i = 0; i < 36; i++) {
			s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
		}
		s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
		s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
		s[8] = s[13] = s[18] = s[23] = "-";

		var uuid = s.join("");
		return uuid;
	}


	var host = isNotBlank(parameters["host"]) ? parameters["host"] : "127.0.0.1";
	var port = isNotBlank(parameters["port"]) ? parameters["port"] : "8083";
	var resourePath = isNotBlank(parameters["resourePath"]) ? parameters["resourePath"] : "/mqtt";
	var username = isNotBlank(parameters["username"]) ? parameters["username"] : MqttClientMv.nextUuid();
	var nickname = isNotBlank(parameters["nickname"]) ? parameters["nickname"] : username;
	var password = isNotBlank(parameters["password"]) ? parameters["password"] : "123456";
	var clientId = isNotBlank(parameters["clientId"]) ? parameters["clientId"] : MqttClientMv.nextUuid();

	$MCP.loadJs = function() {
		var loadTimeSecond = 0;
		try {
			if (mqtt) {
				if (!encryptionMD5) {
					return true;
				}
			}
			if (encryptionMD5) {
				if (calcMD5) {
					return true;
				}
			}
		} catch (e) {
			setTimeout(this.init.bind(this), 1000);
			return false;
		}
		return false;
	};

	$MCP.init = function() {

		if (!this.loadJs()) {
			return;
		}

		this.clientInfo = {
			"host": host,
			"port": port,
			"resourePath": resourePath
		};
		this.options = {
			clean: true,
			connectTimeout: 4000,
			clientId: clientId,
			username: username,
			nickname: nickname,
			password: calcMD5(password)
		}

		this.connectUrl = "ws://" + host + ":" + port + resourePath;
		client = mqtt.connect(this.connectUrl, this.options);
		var _connectUrl = this.connectUrl;
		//当重新连接启动触发回调
		client.on('reconnect', function() {});
		//连接断开后触发的回调
		client.on("close", function() {});

		client.on('message', function(topic, message, packet) {
			// message is Buffer
			var mqttMessage = new CustomEvent('mqttMessage', {
				"detail": {
					topic: topic,
					message: message,
					packet: packet
				}
			})
			if (window.dispatchEvent) {
				window.dispatchEvent(mqttMessage);
			}

			if (window.fireEvent) {
				window.fireEvent(mqttMessage);
			}
		})

		//从broker接收到断开连接的数据包后发出。MQTT 5.0特性
		client.on("disconnect", function(packet) {});
		//客户端脱机下线触发回调
		client.on("offline", function() {});
		//当客户端无法连接或出现错误时触发回调
		client.on("error", (error) => {
			console.log("客户端出现错误....." + error);
		});


		//成功连接后触发的回调
		client.on("connect", function(connack) {
			//订阅某主题
			/**
			 * client.subscribe(topic/topic array/topic object, [options], [callback])
			 * topic:一个string类型的topic或者一个topic数组,也可以是一个对象
			 * options
			 */
			client.subscribe("/client/" + clientId + "/#", {
				qos: 2
			});

			client.subscribe("/user/" + username + "/#", {
				qos: 2
			});

			client.subscribe("/chat/room/public/#", {
				qos: 2
			});

			client.subscribe("/device/control/" + clientId + "/#", {
				qos: 2
			});

			function publish() {};

		});

	}

	var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
	Game_Interpreter.prototype.pluginCommand = function(command, args) {
		_Game_Interpreter_pluginCommand.call(this, command, args);
		// 在这里插入额外的内容
		if (command !== 'MqttClientMv') {
			return;
		}
		var method = args[0].toLowerCase();
		switch (method) {
			case "send":
				$gameMqttClient.publish(args[1], JSON.stringify({
					"message": args[2],
					"clientId": clientId,
					"username": username,
					"nickname": nickname
				}), {
					qos: 2
				});
				break
			case "sub":
				$gameMqttClient.subscribe(args[1], {
					qos: 2
				});
				break
			case "unsub":
				$gameMqttClient.unsubscribe(args[1], {
					qos: 2
				});
				break
			case "send_client":
				$gameMqttClient.publish("/client/" + args[1] + "/", JSON.stringify({
					"message": args[2],
					"clientId": clientId,
					"username": username,
					"nickname": nickname
				}), {
					qos: 2
				});
				break
			case "send_user":
				$gameMqttClient.publish("/user/" + args[1] + "/", JSON.stringify({
					"message": args[2],
					"clientId": clientId,
					"username": username,
					"nickname": nickname
				}), {
					qos: 2
				});
				break
			case "send_public_room":
				$gameMqttClient.publish("/chat/room/public/", JSON.stringify({
					"message": args[1],
					"clientId": clientId,
					"username": username,
					"nickname": nickname
				}), {
					qos: 2
				});
				break
			case "send_room":
				$gameMqttClient.publish("/chat/room/" + args[1] + "/", JSON.stringify({
					"message": args[2],
					"clientId": clientId,
					"username": username,
					"nickname": nickname
				}), {
					qos: 2
				});
				break
		}
	};

	/**
	 * 全局MQTT客户端
	 * @type {MqttClientMv}
	 */
	window.$gameMqttClient = new MqttClientMv();
	window.$gameMqttClient.init();

})();
